package main

import (
	"chat-room/common"
	"chat-room/server/functions"
	"chat-room/server/global"
	"chat-room/server/processor"
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"net"
)

//初始化配置
func init() {
	data, err := ioutil.ReadFile("../config/config.yaml")
	if err != nil {
		fmt.Printf("读取配置文件错误：%v",err)
		return
	}
	err = yaml.Unmarshal(data, &global.YamlConfig)
	if err != nil {
		fmt.Printf("解析配置文件错误：%v",err)
		return
	}

}

func main() {
	var err error
	//初始化mysql连接
	dsn := fmt.Sprintf("%s:%s@%s(%s:%s)/%s",
		global.YamlConfig.Mysql.Username,
		global.YamlConfig.Mysql.Password,
		global.YamlConfig.Mysql.Network,
		global.YamlConfig.Mysql.Host,
		global.YamlConfig.Mysql.Port,
		global.YamlConfig.Mysql.Database,
	)
	global.MysqlDb, err = sql.Open("mysql", dsn)
	if err != nil {
		fmt.Printf("连接数据库失败：%v",err)
		return
	}
	err = global.MysqlDb.Ping()
	if err != nil {
		fmt.Printf("连接数据库失败：%v",err)
		return
	}

	//初始化tcp连接
	global.Listener, err = net.Listen(
		global.YamlConfig.Tcp.Network,
		global.YamlConfig.Tcp.Address + ":" + global.YamlConfig.Tcp.Port,
	)
	if err != nil {
		fmt.Printf("开启监听失败:%v",err)
		return
	}

	//延时关闭数据库和tcp连接
	defer func() {
		_ = global.MysqlDb.Close()
		_ = global.Listener.Close()
	}()

	for {
		conn, err := global.Listener.Accept()
		if err != nil {
			fmt.Printf("客户端连接失败：%v\n",err)
		}else {
			go handel(conn)
		}
	}
}

//处理每一个客户端连接
func handel(conn net.Conn) {
	fmt.Printf("已建立新的连接：%v\n",conn.RemoteAddr())
	//延迟关闭连接
	defer func() {
		err := conn.Close()
		if err != nil {
			fmt.Printf("%v:断开连接失败\n",conn.RemoteAddr())
		}else {
			fmt.Printf("%v:断开连接\n",conn.RemoteAddr())
			//从 global.AllLoginMap 删除,并发送离线信息
			val, _ := global.AllLoginMap.Load(conn)
			if val != nil {
				sendMsg := fmt.Sprintf("%v退出啦",val.(string))
				//先组合消息再删除
				global.AllLoginMap.Delete(conn)
				serverFunctionsEx := &functions.Functions{}
				functionsEx := &common.Functions{}
				messageExByte, _ := serverFunctionsEx.MakeSystemMsgStruct(sendMsg)
				global.AllLoginMap.Range(func(key, value interface{}) bool {
					_ = functionsEx.SendMsg(key.(net.Conn), messageExByte)
					return true
				})
			}
		}
	}()
	//读取数据并调用对应的方法
	ProcessorEx := &processor.Processor{
		Conn:conn,
	}
	ProcessorEx.Handel()
}